package client.net;

import java.io.IOException;

import javax.bluetooth.L2CAPConnection;
import javax.bluetooth.L2CAPConnectionNotifier;
import javax.microedition.io.Connector;

/**
 * @author primianoc
 *
 */
public class L2CapConnectionManager
{

	private String _urlL2CapLocal = null;
	private L2CAPConnectionNotifier _l2capConnectionNotifier = null;
	private L2CAPConnection	_l2capConnection = null;
	private boolean _closed = false;
	private Object _synchCloseSend = new Object();
	private Object _synchCloseReceive = new Object();
	private Object _synchSendReceive = new Object();

	/**
	 * 
	 */
	public L2CapConnectionManager(String urlL2CapLocal)
	{
		_urlL2CapLocal  = urlL2CapLocal;
	}

	public int send(byte data[], boolean blocking)
	{
		int byteSent = -1;

		if(_l2capConnection == null && _closed  == false && blocking == true)
		{
			synchronized(_synchSendReceive)
			{
				while(_l2capConnection == null && _closed == false)
				{
					try
					{
						_synchSendReceive.wait();
					} 
					catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				}
			}
		}

		synchronized(_synchCloseSend)
		{
			if(_l2capConnection != null && _closed == false)
			{
				try
				{
					_l2capConnection.send(data);
					byteSent = data.length;
				} 
				catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}


		return byteSent;
	}

	public int receive(byte buffer[]) throws InterruptedException
	{
		int byteReceived = -1;

		if(_l2capConnectionNotifier == null && _closed == false)
		{
			synchronized(_synchCloseReceive)
			{
				if(_closed == false)
				{
					try
					{
						_l2capConnectionNotifier = 
							(L2CAPConnectionNotifier)Connector.open(_urlL2CapLocal);
					} 
					catch (IOException e)
					{
						e.printStackTrace();

						closeConnectionNotifier();

					}
				}

			}

			/**
			 * Se non è stato possibile istanziare il Notifier restituisco subito -1.
			 */
			if(_l2capConnectionNotifier == null || _closed == true)
			{
				return byteReceived;
			}

		}

		if(_l2capConnection == null && _closed == false)
		{
			synchronized(_synchCloseReceive)
			{
				if(_closed == false)
				{
					try
					{
						_l2capConnection = (L2CAPConnection)_l2capConnectionNotifier.acceptAndOpen();
					} 
					catch (IOException e)
					{
						e.printStackTrace();

						closeConnectionNotifier();
					}
				}

			}

			/**
			 * Se non è stato possibile istanziare la Connection restituisco subito -1.
			 */
			if(_l2capConnectionNotifier == null || _closed == true)
			{
				return byteReceived;
			}
			else
			{
				/**
				 * Sblocco il thread che ha eseguito il metodo
				 * send e che ha eseguito wait.
				 */
				synchronized(_synchSendReceive)
				{
					_synchSendReceive.notify();
				}
			}
		}

		synchronized(_synchCloseReceive)
		{
			if(_l2capConnection != null && _closed == false)
			{
				try
				{
					byteReceived = _l2capConnection.receive(buffer);
				}
				catch (IOException e)
				{
					e.printStackTrace();

					closeConnection();
				}
			}

		}

		return byteReceived;
	}

	public void close()
	{
		synchronized(_synchCloseSend)
		{
			synchronized(_synchCloseReceive)
			{
				closeConnectionNotifier();

				closeConnection();

				_closed = true;
			}
		}

		synchronized(_synchSendReceive)
		{
			_synchSendReceive.notify();
		}
	}

	private void closeConnection()
	{
		if(_l2capConnection != null )
		{
			try
			{
				_l2capConnection.close();
			}
			catch (IOException e1)
			{
				e1.printStackTrace();
			}

			_l2capConnection = null;
		}
	}

	private void closeConnectionNotifier()
	{
		if(_l2capConnectionNotifier != null )
		{
			try
			{
				_l2capConnectionNotifier.close();
			} 
			catch (IOException e1)
			{
				e1.printStackTrace();
			}
			_l2capConnectionNotifier = null;
		}
	}

	public boolean isConnectionOpened()
	{
		if(_l2capConnection != null)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}
